FEXP Solver  1.0.0.0
FEXPNetworkServer.h
Go to the documentation of this file.
1 // © FEXP, FEXPEnterprise Solver, Ing. Vaclav Rek
3 // Server of the hybrid-parallel FEXP solver.
4 // Compiler must support C++ ver.14 and later
6 #ifndef _CFEXPNETWORKSERVER_H_
7 #define _CFEXPNETWORKSERVER_H_
8 #include "FEXPCommon.h"
9 #include "FEXPConcurency.h"
10 #include "FEXPDataContainer.h"
11 #include "FEXPGeom.h"
12 #include "FEXPTopologieKDTree.h"
13 #include "FEXPMultiGraph.h"
14 #include "FEXPNetworkInterface.h"
15 #include "FEXPNetworkWinSocket.h"
17 #include "FEXPResultExport.h"
18 
24 
26 #define SERVER_STOP_FILE_NAME "stop_fexp_server.stop"
27 
29 #define SERVER_TRECK_TRNS_DTA "meim_analysis_rs.csv"
30 
36 // primary template
37 template<typename TTClientRunner, typename TClientThread, typename Tbarrier, typename Enable = void>
38 class CFEXPNetServer { };
41 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
43  <TTClientRunner, TClientThread, Tbarrier,
44  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
45  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
47 {
48 public:
49  virtual ~CFEXPNetServer();
50  // create instance of a server -- Singleton pattern
51  static Ptr<CFEXPNetServer> GetInstance(std::string server_ip, size_t port,
53  {
54  if (SERVER_INSTANCE)
55  return SERVER_INSTANCE;
57  new CFEXPNetServer(server_ip, port, model, exporter, trans_analyzer));
58  return SERVER_INSTANCE;
59  }
60 
61  // override pure virtual member functions
62  virtual void Run () override;
63  virtual void Close() override;
64 protected:
65  // server single instance
67  CFEXPNetServer(std::string server_ip, size_t port,
69  // invoke close action
70  void invoke_close();
71 private:
72  Ptr<ICFEXPDataModelContIntf> _model_cont;
73 
74  void create_socket ();
75  void start_listenning ();
76  void close_socket_conn();
77  void cancel_cl_threads();
78  // client thread creation
79  Ptr<TClientThread> create_client_thread(size_t id, SOCKET client_socket, std::string & ip);
80  void invoke_client_data ();
81 
82  // connection data
83  sockaddr_in _socket_server_adress;
84  SOCKET _socket_server;
85  std::atomic_bool _socket_server_run_and_closed;
86  // data for each of running client threads
87  struct thread_data
88  {
89  size_t _id;
90  std::atomic_bool _state;
91  Ptr<TClientThread> _thread;
92  t_ENetThrdMsg _current_msg_to_send;
93  // queue of messages to proccessed
94  std::atomic_bool _message_server_lunched;
95  std::queue<t_ENetThrdMsg> _message_queue_server_send;
96  std::atomic_bool _message_client_lunched;
97  std::queue<t_ENetThrdMsg> _message_queue_client_send;
98  // client node calculation data
99  Ptr<t_NetCalcData> _calc_data;
100  thread_data(size_t id, Ptr<TClientThread> thread, Ptr<CFEXPSolverConfigSetting> setting) :
101  _id(id), _thread(thread), _state(bool(FEXPCOMMON_DEFAULT_VALUE)),
102  _current_msg_to_send(t_ENetThrdMsg::eThrdMsgCount),
103  _calc_data(CFEXPDataManager<t_NetCalcData>::SafeAllocInstance(setting)),
104  _message_server_lunched(true), _message_client_lunched(true) { }
105  };
106 
107  // data for handling with map of client threads
108  volatile bool _is_thread_to_remove;
109  std::mutex _mtx_client_thread_map_update;
110  std::atomic_bool _flag_server_close;
111  std::atomic_bool _flag_server_closed;
112  std::map<size_t, Ptr<thread_data>> _client_thread_map;
113  // synchronization barrier
114  enum EBarrierUpdate { eNone, eAddUpdate, eRmvUpdate };
115  EBarrierUpdate _barrier_update;
116  std::mutex _mtx_barrier_update;
117  Ptr<Tbarrier> _barrier [t_ENetSynStgs::eSynchrCount];
118  std::atomic_bool _barrier_synchr_end[t_ENetSynStgs::eSynchrCount];
119  std::atomic_bool _barrier_synchr_hit[t_ENetSynStgs::eSynchrCount];
120  void update_barrier (t_ENetSynStgs state);
121  void send_msg_and_wait(t_ENetThrdMsg msg, size_t new_thrd_id);
122 
123  // handling with client threads
124  void add_new_client_thread(size_t id, SOCKET client_socket, std::string & ip);
125  bool synchronize_process (size_t id) noexcept(false);
126  void set_end_client_thread(size_t id);
127  void try_rmv_client_thread();
128  // check if all init. clients are connected
129  std::atomic_bool _main_proc_initialize_control;
130  std::atomic_bool _main_proc_initialize_clients;
131  size_t check_main_process_init();
132  // sending and receiving messages
133  void send_message(size_t id_from, size_t id_to, t_ENetThrdMsg message);
134  t_ENetThrdMsg read_message(size_t id_from, size_t id_to);
135  bool lnch_message(size_t id_from, size_t id_to);
136  // get structure of calculation data belonging to client thread
137  Ptr<t_NetCalcData> get_calc_data(size_t);
138  // stability step resolution process
139  t_fexpcommon_ct _stabil_dt_step;
140  std::mutex _mtx_dtstep_update;
141  void set_stabil_t_step (size_t thrd_id, t_fexpcommon_ct step);
142  void update_global_t_step (size_t new_thrd_id);
143  // analysis of MEIM --> data transfer
144  void analyze_data_transfer(size_t new_thrd_id);
145  size_t _meim_analysis_counter;
146  void write_out_transfer ();
147  // kd-tree of macro elements for assembly of MEIM
148  std::mutex _mtx_kdtree_update;
149  Ptr<ICFEXPTransferAnalyzer> _transfer_analyzer;
150  void add_macro_to_tree(Ptr<CFEXGeomTools::t_BoundBox> bbox, size_t thrd_id, size_t macro_id);
151  // map of client node results
152  Ptr<ICFEXPResultExport> _result_exporter;
153  bool export_results (size_t new_thrd_id);
154  void set_rnt_request();
155  // check end of process
156  void check_proc_end(size_t new_thrd_id);
157 };
158 
159 // member functions
161 //--------------------------------------------------------------------------------------
162 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
164 <TTClientRunner, TClientThread, Tbarrier,
165  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
166  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
168 //--------------------------------------------------------------------------------------
169 
170 //--------------------------------------------------------------------------------------
171 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
173 <TTClientRunner, TClientThread, Tbarrier,
174  typename std::enable_if<std::is_base_of<ICFEXPThreadBase, TClientThread>::value &&
175  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
176  ::CFEXPNetServer(std::string server_ip, size_t port, Ptr<ICFEXPDataModelContIntf> model, Ptr<ICFEXPResultExport> exporter, Ptr<ICFEXPTransferAnalyzer> trans_analyzer)
178  _model_cont(model), _result_exporter(exporter), _stabil_dt_step(GET_MAX_FLT_VAL(t_fexpcommon_ct)), _transfer_analyzer(trans_analyzer),
179  _socket_server(WININVSCK), _main_proc_initialize_control(false), _main_proc_initialize_clients(false),
180  _is_thread_to_remove(false), _socket_server_run_and_closed(false),
181  _flag_server_close(false), _flag_server_closed(false),
182  _barrier_update(EBarrierUpdate::eNone), _meim_analysis_counter(FEXPCOMMON_DEFAULT_VALUE)
183 //--------------------------------------------------------------------------------------
184 {
185 #define DEFAULT_SERVER_BARRIER_COUNT 1
186  size_t idx;
187  FEXPCOMMON_FOREACH(size_t(t_ENetSynStgs::eStartPoint ),
188  size_t(t_ENetSynStgs::eSynchrCount) - 1, idx)
189  {
191  _barrier_synchr_end[idx] = false;
192  _barrier_synchr_hit[idx] = false;
193  }
194 }
195 
196 //--------------------------------------------------------------------------------------
197 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
199 <TTClientRunner, TClientThread, Tbarrier,
200  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
201  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
202  ::~CFEXPNetServer()
203 //--------------------------------------------------------------------------------------
204 {
205  try
206  {
207  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: Destructing server connection object node ID: " + CFEXPBaseConvers::NumberToString(GetId()) + " ...");
208  cancel_cl_threads();
209  close_socket_conn();
210  }
211  catch (const std::exception & ex)
212  {
214  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "An exception occurred:");
215  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> " + ex.what());
216  }
217 }
218 
221 //--------------------------------------------------------------------------------------
222 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
223 void CFEXPNetServer
224 <TTClientRunner, TClientThread, Tbarrier,
225  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
226  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
227  ::Run()
228 //--------------------------------------------------------------------------------------
229 {
230 #define SERVER_NEW_CLIENT_CONNECT 1
231  if (_connection_start.load())
232  return;
233  // run server thread -- non-blocking accept server --> timeout_ptr != nullptr
234  auto result = CFEXPAsyncRunner::RunProcedureTask([this]
235  {
236  // start listenning on port
237  start_listenning();
238  // count connected clients -- generate ID
239  auto client_id_generator = size_t(FEXPCOMMON_DEFAULT_VALUE);
240  auto synchronize_stat_id = size_t(t_ENetSynStgs::eStartPoint); auto new_thrd_id = size_t(FEXPCOMMON_DEFAULT_VALUE);
241  auto init_start_clnts_ok = false;
242  while (!_flag_server_close.load() && !_socket_server_run_and_closed.load())
243  {
244  // network calculation synchronization points
245  switch (synchronize_stat_id)
246  {
247  case t_ENetSynStgs::eStartPoint:
248  update_barrier(t_ENetSynStgs(synchronize_stat_id));
249  // synchronize and move to new stage
250  if (!synchronize_process(synchronize_stat_id++))
251  return;
252  break;
253  case t_ENetSynStgs::eBeforeClientUpdate:
254  update_barrier(t_ENetSynStgs(synchronize_stat_id));
255  // send current data to clients
256  invoke_client_data();
257  // synchronize and move to new stage
258  if (!synchronize_process(synchronize_stat_id++))
259  return;
260  break;
261  case t_ENetSynStgs::eClientUpdate:
262  {
263  fd_set read_set; FD_ZERO(&read_set); FD_SET(_socket_server, &read_set);
264  // the maximum time for select to wait, provided in the form of a TIMEVAL structure,
265  timeval timeout;
266  timeout.tv_sec = FEXPCOMMON_DEFAULT_VALUE;
267  timeout.tv_usec = FEXPCOMMON_DEFAULT_VALUE;
268  // set the timeout parameter to nullptr for blocking operations
269  auto timeout_ptr = &timeout /*nullptr*/;
270  // new number of threads for update of thread barrier
271  auto new_thr_num = size_t(FEXPCOMMON_DEFAULT_VALUE);
272  // determines the status of one or more sockets, waiting if necessary, to perform synchronous I/O.
273  if (select(_socket_server, &read_set, nullptr, nullptr, timeout_ptr) != SERVER_NEW_CLIENT_CONNECT)
274  try_rmv_client_thread(); // remove ended client thread if it is need
275  else
276  {
277  // new client node connected
278  sockaddr_in from; int from_len = sizeof(from);
279  new_thrd_id = ++client_id_generator;
280  auto new_client_socket = accept(_socket_server, (struct sockaddr*)&from, &from_len);
281  auto new_client_ip_adr = std::string(inet_ntoa(from.sin_addr));
282  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: New client connected:");
283  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> IPv4: " + new_client_ip_adr);
284  add_new_client_thread(new_thrd_id, new_client_socket, new_client_ip_adr);
285  }
286  }
287 
288  // check if main process can start
289  check_main_process_init();
290  // synchronize and move to new stage
291  if (!synchronize_process(synchronize_stat_id++))
292  return;
293  break;
294  case t_ENetSynStgs::eAfterClientUpdate:
295  // synchronize and move to new stage
296  if (!synchronize_process(synchronize_stat_id++))
297  return;
298  break;
299  case t_ENetSynStgs::eEndPoint:
300  update_barrier(t_ENetSynStgs(synchronize_stat_id));
301  // synchronize and move to new stage
302  if (!synchronize_process(synchronize_stat_id++))
303  return;
304  break;
305  case t_ENetSynStgs::eCheckCalcEnd:
306  update_barrier (t_ENetSynStgs(synchronize_stat_id));
307  // receive info about calculation process
308  send_msg_and_wait(t_ENetThrdMsg::eEnd, new_thrd_id);
309  // synchronize and move to new stage
310  if (!synchronize_process(synchronize_stat_id++))
311  return;
312  break;
313  case t_ENetSynStgs::eStartNewTimeStep:
314  update_barrier(t_ENetSynStgs(synchronize_stat_id));
315  // export results --> send last data to export --> end process
316  check_proc_end(new_thrd_id);
317  // synchronize and move to new stage
318  if (!synchronize_process(synchronize_stat_id++))
319  return;
320  break;
321  case t_ENetSynStgs::eResults:
322  update_barrier (t_ENetSynStgs(synchronize_stat_id));
323  // receive calculation results from clients
324  send_msg_and_wait(t_ENetThrdMsg::eCalcResults, new_thrd_id);
325  // export results
326  export_results (new_thrd_id);
327  // synchronize and move to new stage
328  if (!synchronize_process(synchronize_stat_id++))
329  return;
330  break;
331  case t_ENetSynStgs::eStabilityControl:
332  update_barrier (t_ENetSynStgs(synchronize_stat_id));
333  // receive stabil time steps from clients
334  send_msg_and_wait (t_ENetThrdMsg::eStep, new_thrd_id);
335  // set global time step
336  update_global_t_step(new_thrd_id);
337  // invoke global time step preparation
338  send_msg_and_wait (t_ENetThrdMsg::eStep, new_thrd_id);
339  // synchronize and move to new stage
340  if (!synchronize_process(synchronize_stat_id++))
341  return;
342  break;
343  case t_ENetSynStgs::eDataExchange:
344  update_barrier (t_ENetSynStgs(synchronize_stat_id));
345  // receive bounding boxes of macro models
346  send_msg_and_wait (t_ENetThrdMsg::eBoundingBox, new_thrd_id);
347  // MEIM analysis
348  analyze_data_transfer(new_thrd_id);
349  // invoke message again to invoke waiting for data preparation
350  send_msg_and_wait (t_ENetThrdMsg::eBoundingBox, new_thrd_id);
351  // --> 1. data from clients to server
352  send_msg_and_wait (t_ENetThrdMsg::eBoundingBox, new_thrd_id);
353  // --> 2. data from server to clients
354  // synchronize and move to new stage
355  if (!synchronize_process(synchronize_stat_id++))
356  return;
357  break;
358  case t_ENetSynStgs::eEndLoop:
359  update_barrier(t_ENetSynStgs(synchronize_stat_id));
360  // in common situation there are no data to exchange
361  if (_main_proc_initialize_control && _main_proc_initialize_clients)
362  {
363  // reset data analyzer
364  if (_transfer_analyzer)
365  _transfer_analyzer->Reset();
366  }
367  // synchronize
368  if (!synchronize_process(synchronize_stat_id))
369  return;
370  // move to new stage (reset value --> new synchronization loop)
371  synchronize_stat_id = size_t(t_ENetSynStgs::eStartPoint);
372  // reset added last client id
373  new_thrd_id = FEXPCOMMON_DEFAULT_VALUE;
374  // reset time step value
375  _stabil_dt_step = GET_MAX_FLT_VAL(t_fexpcommon_ct);
376  break;
377  default:
378  FEXPCOMMON_EXCEPTION("Error: Wrong process synchronization state!!!");
379  }
380  }
381  }, false, "Server Process", true);
382  // invoke close event (stop server)
383  invoke_close(); _flag_server_closed.store(true);
384 }
385 
386 //--------------------------------------------------------------------------------------
387 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
388 void CFEXPNetServer
389 <TTClientRunner, TClientThread, Tbarrier,
390  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
391  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
392  ::update_barrier(t_ENetSynStgs state)
393 //--------------------------------------------------------------------------------------
394 {
395  const size_t distance = size_t(t_ENetSynStgs::eEndPoint) - size_t(t_ENetSynStgs::eClientUpdate);
396  switch (state)
397  {
398  case t_ENetSynStgs::eStartPoint :
399  // the end of permutation update of number of threads in barriers if new thread was added
400  if (_barrier_update == EBarrierUpdate::eAddUpdate)
401  {
402  _barrier[t_ENetSynStgs::eBeforeClientUpdate] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
403  _barrier[t_ENetSynStgs::eDataExchange ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
404  }
405  break;
406  case t_ENetSynStgs::eBeforeClientUpdate:
407  if (_barrier_update == EBarrierUpdate::eAddUpdate)
408  {
409  _barrier[t_ENetSynStgs::eEndLoop] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
410  // reset barrier update control value
411  _barrier_update = EBarrierUpdate::eNone;
412  }
413  break;
414  case t_ENetSynStgs::eClientUpdate :
415  case t_ENetSynStgs::eAfterClientUpdate :
416  case t_ENetSynStgs::eEndPoint :
417  if (_barrier_update == EBarrierUpdate::eAddUpdate)
418  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
419  break;
420  case t_ENetSynStgs::eCheckCalcEnd :
421  // if number of thread was changed update number of threads in client control bock
422  // --> if new thread was added start permutation update of number of threads in barriers
423  if (_barrier_update == EBarrierUpdate::eAddUpdate)
424  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
425  break;
426  case t_ENetSynStgs::eStartNewTimeStep :
427  // if number of thread was changed update number of threads in client control bock
428  // --> if new thread was added start permutation update of number of threads in barriers
429  if (_barrier_update == EBarrierUpdate::eAddUpdate)
430  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
431  break;
432  case t_ENetSynStgs::eResults:
433  // continue permutation update of number of threads in barriers if new thread was added
434  if (_barrier_update == EBarrierUpdate::eAddUpdate)
435  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
436  break;
437  case t_ENetSynStgs::eStabilityControl :
438  // continue permutation update of number of threads in barriers if new thread was added
439  if (_barrier_update == EBarrierUpdate::eAddUpdate)
440  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
441  break;
442  case t_ENetSynStgs::eDataExchange :
443  // continue permutation update of number of threads in barriers if new thread was added
444  if (_barrier_update == EBarrierUpdate::eAddUpdate)
445  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
446  break;
447  case t_ENetSynStgs::eEndLoop :
448  // continue permutation update of number of threads in barriers if new thread was added
449  if (_barrier_update == EBarrierUpdate::eAddUpdate)
450  _barrier[state - distance] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
451  break;
452  default:
453  FEXPCOMMON_EXCEPTION("Error: Unknown type of synchronization phase!!!");
454  }
455 }
456 
457 //--------------------------------------------------------------------------------------
458 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
459 void CFEXPNetServer
460 <TTClientRunner, TClientThread, Tbarrier,
461  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
462  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
463  ::send_msg_and_wait(t_ENetThrdMsg msg, size_t new_thrd_id)
464 //--------------------------------------------------------------------------------------
465 {
466  if (!(_main_proc_initialize_control && _main_proc_initialize_clients))
467  return;
468 
469  // send data to get current bounding boxes except from last added client
470  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
471  {
472  auto id = (*IT).first;
473  if (id == new_thrd_id)
474  continue;
475  send_message(GetId(), id, msg);
476  }
477  // wait to read message
478  auto msg_read_counter = size_t(FEXPCOMMON_DEFAULT_VALUE);
479  while (msg_read_counter != _client_thread_map.size())
480  {
481  msg_read_counter = size_t(FEXPCOMMON_DEFAULT_VALUE);
482  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
483  {
484  auto id = (*IT).first;
485  if (id == new_thrd_id)
486  continue;
487  if (lnch_message(GetId(), (*IT).first))
488  ++msg_read_counter;
489  }
490  if (new_thrd_id != FEXPCOMMON_DEFAULT_VALUE)
491  ++msg_read_counter;
492  }
493 }
494 
495 //--------------------------------------------------------------------------------------
496 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
498 <TTClientRunner, TClientThread, Tbarrier,
499  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
500  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
501  ::create_client_thread(size_t id, SOCKET client_socket, std::string & ip)
502 //--------------------------------------------------------------------------------------
503 {
504  return CFEXPDataManager<TClientThread>::SafeAllocInstance([this](auto client) { client->Run(); },
505  CFEXPDataManager<TTClientRunner>::SafeAllocInstance(client_socket, ip, id, GetServerNodeIP(),
506  [this](auto id_from, auto id_to ) { return read_message(id_from, id_to); },
507  [this](auto id_from, auto id_to ) { return lnch_message(id_from, id_to); },
508  [this](auto id_from, auto id_to, auto mssg) { send_message(id_from, id_to, mssg); },
509  [this](auto id_from ) { return get_calc_data(id_from); },
510  [this](auto id_from ) { set_end_client_thread(id_from); },
511  [this](auto synstat ) { return synchronize_process(synstat); },
512  [this](auto id_from, auto dt ) { set_stabil_t_step(id_from, dt); },
513  [this](auto id_from, auto bbox , auto mid ) { add_macro_to_tree(bbox, id_from, mid); }));
514 }
515 
516 //--------------------------------------------------------------------------------------
517 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
518 void CFEXPNetServer
519 <TTClientRunner, TClientThread, Tbarrier,
520  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
521  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
522  ::invoke_client_data()
523 //--------------------------------------------------------------------------------------
524 {
525  Ptr<std::vector<size_t>> schedule; std::queue<size_t> init_models; std::queue<size_t> init_models_schedule;
526  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
527  {
528  auto key = (*IT).first;
529  auto dta = (*IT).second;
530  auto msg = dta->_current_msg_to_send;
531  switch (msg)
532  {
533  case t_ENetThrdMsg::eInit:
534  {
535  // server setting
537  _model_cont->GetModelElement(ICFEXPSetting::ESettingType::eSolver, ESystemElementType::eSetting));
538  if (!schedule)
539  {
540  schedule = setting->GetSimpleModelSchedule();
541  // fill queue with models
542  FEXPCOMMON_FOREACH_ITER_FNC(setting->GetFileContent(), { init_models.push(IT.first); });
543  // fill queue with number of models for each client
544  FEXPCOMMON_FOREACH_ITER_FNC(*schedule.get(), { init_models_schedule.push(IT); });
545  }
546  auto default_model = init_models.empty();
547  auto ifile_content = [=](auto id)
548  {
549  return (default_model ?
550  setting->GetFileContentDefault() :
551  setting->GetFileContent())[id];
552  };
553  // set default empty data if no other model is available
554  if (default_model)
555  {
556  FEXPCOMMON_FOREACH_ITER_FNC(setting->GetFileContentDefault(), { init_models.push(IT.first); });
557  init_models_schedule.push(init_models.size());
558  }
559  // add number of models for each client
560  size_t idx; size_t mode_count = init_models_schedule.front();
561  FEXPCOMMON_FOREACH(FEXPCOMMON_DEFAULT_VALUE, mode_count - 1, idx)
562  {
563  auto model_id = init_models.front();
564  dta->_calc_data->CURRENT_DATA_FOR_SEND.insert(
565  MAP_PAIR(CFEXPBaseConvers::NumberToString(model_id), ifile_content(model_id)));
566  init_models.pop();
567  }
568  init_models_schedule.pop();
569  // start client initialize completed
570  _main_proc_initialize_clients = true;
571  }
572  break;
573  case t_ENetThrdMsg::eRuntimeInit:
574  {
575  // server setting
577  _model_cont->GetModelElement(ICFEXPSetting::ESettingType::eSolver, ESystemElementType::eSetting));
578  FEXPCOMMON_FOREACH_ITER_FNC(setting->GetFileContentDefault(),
579  {
580  // send empty data and let client wait for data exchange event
581  dta->_calc_data->CURRENT_DATA_FOR_SEND.insert(
583  });
584  }
585  break;
586  default:
587  msg = t_ENetThrdMsg::eContinueProc; // continue in process
588  }
589  // send message to client
590  send_message(GetId(), key, msg);
591  // reset message
592  dta->_current_msg_to_send = t_ENetThrdMsg::eThrdMsgCount;
593  };
594 }
595 
596 //--------------------------------------------------------------------------------------
597 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
598 void CFEXPNetServer
599 <TTClientRunner, TClientThread, Tbarrier,
600  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
601  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
602  ::add_new_client_thread(size_t id, SOCKET client_socket, std::string & ip)
603 //--------------------------------------------------------------------------------------
604 {
605 #define MAP_THREAD_IDX FEXPCOMMON_DEFAULT_INDX
606 #define MAP_THREAD_VALUE_IDX 1
607  if (_client_thread_map.count(id))
608  FEXPCOMMON_EXCEPTION("Error: Try add new client thread with existing ID!!!");
609 
610  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
611  lock.lock();
612  auto cnt_tm = std::time(nullptr);
613  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: New cluster node ID " + CFEXPBaseConvers::NumberToString(id) + ":");
614  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> Connected at " + std::string(std::ctime(&cnt_tm)));
615  // create new client thread data, start thread and detach
616  auto server_thread_data = CFEXPDataManager<thread_data>::SafeAllocInstance(id, create_client_thread(id, client_socket, ip),
618  _model_cont->GetModelElement(ICFEXPSetting::ESettingType::eSolver, ESystemElementType::eSetting)));
619  // add thread data to map
620  _client_thread_map.insert(MAP_PAIR(server_thread_data->_id, server_thread_data));
621  // update number of threads in eStartPoint barrier only
622  // --> permutation process
623  _barrier[t_ENetSynStgs::eStartPoint] =
624  CFEXPDataManager<Tbarrier>::SafeAllocInstance(_client_thread_map.size() + 1);
625  // start thread and detach
626  server_thread_data->_thread->StartThread();
627  server_thread_data->_thread->Detach();
628  // set active state
629  server_thread_data->_state = true;
630  // if calculation is running and new client is connected --> data are required
631  server_thread_data->_current_msg_to_send = _main_proc_initialize_control ? t_ENetThrdMsg::eRuntimeInit : t_ENetThrdMsg::eContinueProc;
632  // need update barriers
633  _barrier_update = EBarrierUpdate::eAddUpdate;
634  // set request for runtime data printing
635  set_rnt_request();
636  lock.unlock();
637 }
638 
639 //--------------------------------------------------------------------------------------
640 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
641 bool CFEXPNetServer
642 <TTClientRunner, TClientThread, Tbarrier,
643  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
644  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
645  ::synchronize_process(size_t id) noexcept(false)
646 //--------------------------------------------------------------------------------------
647 {
648  if(id >= t_ENetSynStgs::eSynchrCount)
649  FEXPCOMMON_EXCEPTION("Error: Wrong process synchronization state!!!");
650  if (_barrier_synchr_end[id].load())
651  return false;
652  _barrier_synchr_hit[id].store(true );
653  _barrier [id]->SynchronizeThreads();
654  _barrier_synchr_hit[id].store(false);
655  return true;
656 }
657 
658 //--------------------------------------------------------------------------------------
659 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
660 void CFEXPNetServer
661 <TTClientRunner, TClientThread, Tbarrier,
662  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
663  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
664  ::set_end_client_thread(size_t id)
665 //--------------------------------------------------------------------------------------
666 {
667  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
668  lock.lock();
669  if (_client_thread_map.count(id))
670  {
671  auto cnt_tm = std::time(nullptr);
672  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: Cluster node ID " + CFEXPBaseConvers::NumberToString(id) + ":");
673  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> Ended at " + std::string(std::ctime(&cnt_tm)));
674  _client_thread_map[id]->_state = !(_is_thread_to_remove = true);
675  }
676  lock.unlock();
677 }
678 
679 //--------------------------------------------------------------------------------------
680 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
681 void CFEXPNetServer
682 <TTClientRunner, TClientThread, Tbarrier,
683  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
684  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
685  ::try_rmv_client_thread()
686 //--------------------------------------------------------------------------------------
687 {
688  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
689  lock.lock();
690  if (_is_thread_to_remove)
691  {
692  std::vector<size_t> to_remove;
693  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map,
694  {
695  if (!IT.second->_state)
696  to_remove.push_back(IT.first);
697  });
698  size_t idx; auto endidx = to_remove.size() - 1;
700  {
701  auto cnt_tm = std::time(nullptr);
702  auto trd_id = to_remove[idx];
703  // remove thread data from map
704  _client_thread_map.erase(_client_thread_map.find(trd_id));
705  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: Cluster node ID " + CFEXPBaseConvers::NumberToString(trd_id) + ":");
706  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> Removed at " + std::string(std::ctime(&cnt_tm)));
707  }
708  _is_thread_to_remove = false;
709  // check if need to update barriers
710  _barrier_update = !to_remove.empty() ? EBarrierUpdate::eRmvUpdate : EBarrierUpdate::eNone;
711  // update number of threads in barriers if it is need
712  if (_barrier_update == EBarrierUpdate::eRmvUpdate)
713  {
714  auto tread_count = _client_thread_map.size() + 1;
715  _barrier[t_ENetSynStgs::eStartPoint ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
716  _barrier[t_ENetSynStgs::eAfterClientUpdate] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
717  _barrier[t_ENetSynStgs::eEndPoint ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
718  _barrier[t_ENetSynStgs::eCheckCalcEnd ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
719  _barrier[t_ENetSynStgs::eStartNewTimeStep ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
720  _barrier[t_ENetSynStgs::eResults ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
721  _barrier[t_ENetSynStgs::eStabilityControl ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
722  _barrier[t_ENetSynStgs::eDataExchange ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
723  _barrier[t_ENetSynStgs::eEndLoop ] = CFEXPDataManager<Tbarrier>::SafeAllocInstance(tread_count);
724  }
725  }
726  lock.unlock();
727 }
728 
729 //--------------------------------------------------------------------------------------
730 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
731 size_t CFEXPNetServer
732 <TTClientRunner, TClientThread, Tbarrier,
733  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
734  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
735  ::check_main_process_init()
736 //--------------------------------------------------------------------------------------
737 {
738  auto result = size_t(FEXPCOMMON_DEFAULT_VALUE);
739  if (_main_proc_initialize_control)
740  return result;
741 
742  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
743  lock.lock();
744  size_t counter = FEXPCOMMON_DEFAULT_VALUE;
745  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map,
746  {
747  if (IT.second->_state)
748  ++counter;
749  });
750  // get server setting
752  _model_cont->GetModelElement(ICFEXPSetting::ESettingType::eSolver, ESystemElementType::eSetting));
753  // check number of clients to start calculation
754  result = setting->GetInitClientNumber() - counter;
755  _main_proc_initialize_control.store(!_main_proc_initialize_control ? result == FEXPCOMMON_DEFAULT_VALUE : _main_proc_initialize_control);
756  lock.unlock();
757  // print out start main process
758  if (_main_proc_initialize_control)
759  {
760  // add init message to process
761  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map, { IT.second->_current_msg_to_send = t_ENetThrdMsg::eInit; });
762  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: Initial number of cluster nodes has been connected:");
763  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "--> Calculation will start immediately!");
764  }
765  return result;
766 }
767 
768 //--------------------------------------------------------------------------------------
769 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
770 void CFEXPNetServer
771 <TTClientRunner, TClientThread, Tbarrier,
772  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
773  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
774  ::send_message(size_t id_from, size_t id_to, t_ENetThrdMsg message)
775 //--------------------------------------------------------------------------------------
776 {
777  if (message == t_ENetThrdMsg::eThrdMsgCount)
778  return;
779 
780  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
781  lock.lock();
782  if (GetId() == id_from)
783  {
784  // messages from server to client
785  auto thread = _client_thread_map[id_to];
786  if (thread->_message_client_lunched)
787  thread->_message_client_lunched.store(false);
788  thread->_message_queue_server_send.push(message);
789  }
790  else
791  {
792  // messages from client to server
793  auto thread = _client_thread_map[id_from];
794  if (thread->_message_server_lunched)
795  thread->_message_server_lunched.store(false);
796  thread->_message_queue_client_send.push(message);
797  }
798  lock.unlock();
799 }
800 
801 //--------------------------------------------------------------------------------------
802 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
803 bool CFEXPNetServer
804 <TTClientRunner, TClientThread, Tbarrier,
805  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
806  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
807  ::lnch_message(size_t id_from, size_t id_to)
808 //--------------------------------------------------------------------------------------
809 {
810  return GetId() == id_from ?
811  _client_thread_map[id_to ]->_message_client_lunched.load() :
812  _client_thread_map[id_from]->_message_server_lunched.load();
813 }
814 
815 //--------------------------------------------------------------------------------------
816 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
818 <TTClientRunner, TClientThread, Tbarrier,
819  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
820  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
821  ::read_message(size_t id_from, size_t id_to)
822 //--------------------------------------------------------------------------------------
823 {
824  t_ENetThrdMsg message;
825  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
826  lock.lock();
827  if (GetId() == id_from)
828  {
829  auto thread = _client_thread_map[id_to];
830  if (!thread->_message_client_lunched.load() && !thread->_message_queue_server_send.empty())
831  {
832  message = thread->_message_queue_server_send.front();
833  thread->_message_queue_server_send.pop();
834  if (thread->_message_queue_server_send.empty())
835  thread->_message_client_lunched.store(true);
836  }
837  else
838  message = t_ENetThrdMsg::eThrdMsgCount;
839  }
840  else
841  {
842  auto thread = _client_thread_map[id_from];
843  if (!thread->_message_server_lunched.load() && !thread->_message_queue_client_send.empty())
844  {
845  message = thread->_message_queue_client_send.front();
846  thread->_message_queue_client_send.pop();
847  if (thread->_message_queue_client_send.empty())
848  thread->_message_server_lunched.store(true);
849  }
850  else
851  message = t_ENetThrdMsg::eThrdMsgCount;
852  }
853  lock.unlock();
854  return message;
855 }
856 
857 //--------------------------------------------------------------------------------------
858 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
860 <TTClientRunner, TClientThread, Tbarrier,
861  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
862  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
863  ::get_calc_data(size_t id)
864 //--------------------------------------------------------------------------------------
865 {
866  Ptr<t_NetCalcData> data;
867  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
868  lock.lock();
869  if (_client_thread_map.count(id))
870  data = _client_thread_map[id]->_calc_data;
871  lock.unlock();
872  return data;
873 }
874 
875 //--------------------------------------------------------------------------------------
876 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
877 bool CFEXPNetServer
878 <TTClientRunner, TClientThread, Tbarrier,
879  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
880  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
881  ::export_results(size_t new_thrd_id)
882 //--------------------------------------------------------------------------------------
883 {
884  auto result_exported = false;
885  if (!(_main_proc_initialize_control && _main_proc_initialize_clients))
886  return result_exported;
887 
888  std::map<size_t, Ptr<CFEXPCalculationModelNodeResult>> thread_result_map;
889  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
890  {
891  auto thrd_id = (*IT).first;
892  if (thrd_id == new_thrd_id)
893  continue;
894  auto results = (*IT).second->_calc_data->CURRENT_DATA_RECEIVED;
895  if (results.empty())
896  continue;
897 
898  // print out runtime calculation data
899  auto resulto_rows = results["rso"];
900  if (resulto_rows && !resulto_rows->empty())
901  {
902  auto output = resulto_rows->at(FEXPCOMMON_DEFAULT_INDX);
903  if (output != FEXPCOMMON_EMPTY_STRING)
904  CFEXPLog::WriteLine(output);
905  }
906 
907  auto result_rows = results["rs"];
908  if (!result_rows || result_rows->empty())
909  continue;
910  // read serialized results
913  reader->Read();
914  // build result instance
916  ::SafeAllocInstance(_model_cont, FEXPCOMMON_EMPTY_STRING, FEXPCOMMON_EMPTY_STRING, FEXPCOMMON_EMPTY_STRING)->BuildModel(
917  CFEXPBaseConvers::NumberToString(thrd_id), reader->GetFileContent(),
918  FEXPCOMMON_DYNCAST(CFEXPFEInpContBase, ICFEXPDataContIntf, reader->GetInputContainer()));
919  if (_model_cont->ItemCount(ESystemElementType::eResult) > 1)
920  FEXPCOMMON_EXCEPTION("Error: Data from more time levels arrived!!!");
921  // add to result map
922  _model_cont->IterateModElems([&thread_result_map, &thrd_id](auto item)
923  { thread_result_map.insert(MAP_PAIR(thrd_id, FEXPCOMMON_STACAST(ICFEXPModelDataIntf, CFEXPCalculationModelNodeResult, item))); return true; },
925 
926  // clear lunched result data
927  results.clear();
928  // clear results from current client and prepare for next one
929  _model_cont->RemoveAll(ESystemElementType::eResult);
930  }
931  if (thread_result_map.empty())
932  return result_exported;
933 
935  FEXPCOMMON_FOREACH_ITER(thread_result_map)
936  {
937  if (!results)
938  {
939  results = (*IT).second;
940  continue;
941  }
942  // node results
943  FEXPCOMMON_FOREACH_ITER_FNC((*IT).second->GetNodeResults (), { results->GetNodeResults ().push_back(IT); });
944  // fe connectivity
945  FEXPCOMMON_FOREACH_ITER_FNC((*IT).second->GetConnectivity(), { results->GetConnectivity().push_back(IT); });
946  }
947 
948  // final export of results
949  if (_result_exporter)
950  _result_exporter->Write(results);
951  return !result_exported;
952 }
953 
954 //--------------------------------------------------------------------------------------
955 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
956 void CFEXPNetServer
957 <TTClientRunner, TClientThread, Tbarrier,
958  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
959  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
960  ::set_rnt_request()
961 //--------------------------------------------------------------------------------------
962 {
963  // server setting
965  _model_cont->GetModelElement(ICFEXPSetting::ESettingType::eSolver, ESystemElementType::eSetting));
966 
967  auto dkey = "rso";
968  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
969  {
970  if (!IT->second->_calc_data->CURRENT_DATA_FOR_POUT.empty())
971  continue;
972  IT->second->_calc_data->CURRENT_DATA_FOR_POUT
973  .insert(MAP_PAIR(dkey, CFEXPDataManager<std::vector<std::string>>::SafeAllocInstance()));
974  IT->second->_calc_data->CURRENT_DATA_FOR_POUT[dkey]->push_back(CFEXPBaseConvers::NumberToString(setting->NodeIdToShow ()));
975  IT->second->_calc_data->CURRENT_DATA_FOR_POUT[dkey]->push_back(CFEXPBaseConvers::NumberToString(setting->NodeDofToShow()));
976  }
977 }
978 
979 //--------------------------------------------------------------------------------------
980 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
981 void CFEXPNetServer
982 <TTClientRunner, TClientThread, Tbarrier,
983  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
984  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
985  ::set_stabil_t_step(size_t thrd_id, t_fexpcommon_ct step)
986 //--------------------------------------------------------------------------------------
987 {
988  std::unique_lock<std::mutex> lock(_mtx_dtstep_update, std::defer_lock);
989  lock.lock();
990  _stabil_dt_step = step < _stabil_dt_step ? step : _stabil_dt_step;
991  lock.unlock();
992 }
993 
994 //--------------------------------------------------------------------------------------
995 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
996 void CFEXPNetServer
997 <TTClientRunner, TClientThread, Tbarrier,
998  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
999  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1000  ::update_global_t_step(size_t new_thrd_id)
1001 //--------------------------------------------------------------------------------------
1002 {
1003  if (!(_main_proc_initialize_control && _main_proc_initialize_clients))
1004  return;
1005  auto dkey = "dt";
1006  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
1007  {
1008  if (IT->first == new_thrd_id)
1009  continue;
1010  IT->second->_calc_data->CURRENT_DATA_FOR_SEND
1011  .insert(MAP_PAIR(dkey, CFEXPDataManager<std::vector<std::string>>::SafeAllocInstance()));
1012  IT->second->_calc_data->CURRENT_DATA_FOR_SEND[dkey]->push_back(CFEXPBaseConvers::NumberToString(_stabil_dt_step));
1013  }
1014 }
1015 
1016 //--------------------------------------------------------------------------------------
1017 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1018 void CFEXPNetServer
1019 <TTClientRunner, TClientThread, Tbarrier,
1020  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1021  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1022  ::add_macro_to_tree(Ptr<CFEXGeomTools::t_BoundBox> bbox, size_t thrd_id, size_t macro_id)
1023 //--------------------------------------------------------------------------------------
1024 {
1025  if (!_transfer_analyzer)
1026  return;
1027  std::unique_lock<std::mutex> lock(_mtx_kdtree_update, std::defer_lock);
1028  lock.lock();
1029  // add macro bounding box into the MEIM analyzer
1030  _transfer_analyzer->AddMacro(bbox, macro_id, thrd_id);
1031  lock.unlock();
1032 }
1033 
1034 //--------------------------------------------------------------------------------------
1035 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1036 void CFEXPNetServer
1037 <TTClientRunner, TClientThread, Tbarrier,
1038  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1039  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1040  ::analyze_data_transfer(size_t new_thrd_id)
1041 //--------------------------------------------------------------------------------------
1042 {
1043  if (!(_main_proc_initialize_control && _main_proc_initialize_clients))
1044  return;
1045  ++_meim_analysis_counter;
1046  // clear data from previous session
1047  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map,
1048  {
1049  IT.second->_calc_data->MODEL_DATA_GET.clear();
1050  IT.second->_calc_data->MODEL_DATA_SET.clear();
1051  });
1052  // analyze data transfer
1053  if (!_transfer_analyzer->Analyze())
1054  return;
1055  // save data from analysis for data transfer
1056  auto data_from = _transfer_analyzer->GetTransferComputerModelFrom ();
1057  auto data_to = _transfer_analyzer->GetTransferComputerModelTo ();
1058  auto data_assoc = _transfer_analyzer->GetMacroToComputerAssociation();
1059  if (data_from.empty() && data_to.empty())
1060  return;
1061  else if (data_from.empty() || data_to.empty())
1062  FEXPCOMMON_EXCEPTION("Error: Wrong data transfer analysis!!!");
1063  CFEXPLog::WriteLine(FEXPCOMMON_DFLT_TXT + "Info: Transfer of data required.");
1064  // store data for data transfer
1065  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
1066  {
1067  auto tid = IT->first;
1068  auto dta = IT->second->_calc_data;
1069  if (data_from.count(tid))
1070  FEXPCOMMON_FOREACH_ITER_FNC(data_from[tid], { dta->MODEL_DATA_GET.push_back(IT); });
1071  if (data_to.count(tid))
1072  FEXPCOMMON_FOREACH_ITER_FNC(data_to [tid], { dta->MODEL_DATA_SET.push_back(std::make_tuple(IT, data_assoc[IT])); });
1073  };
1074  // try to write current transfer data to file
1075  write_out_transfer();
1076 }
1077 
1078 //--------------------------------------------------------------------------------------
1079 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1080 void CFEXPNetServer
1081 <TTClientRunner, TClientThread, Tbarrier,
1082  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1083  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1084  ::write_out_transfer()
1085 //--------------------------------------------------------------------------------------
1086 {
1087  std::ofstream file;
1088  file.open(SERVER_TRECK_TRNS_DTA, std::ios::out | std::ios::app);
1089  if (file.fail())
1090  return;
1091  file << "MEIM analysis count (transfer required): " << _meim_analysis_counter << std::endl;
1092  // transfer "from"
1093  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
1094  {
1095  auto tid = IT->first;
1096  auto dta = IT->second->_calc_data;
1097  if (dta->MODEL_DATA_GET.empty())
1098  continue;
1099  file << "Data from: c" << tid << std::endl;
1100  FEXPCOMMON_FOREACH_ITER_FNC(dta->MODEL_DATA_GET,
1101  { auto value = IT; file << "m" << value << FEXPCOMMON_DELIMITER; });
1102  file << std::endl;
1103  }
1104  // transfer "to"
1105  FEXPCOMMON_FOREACH_ITER(_client_thread_map)
1106  {
1107  auto tid = IT->first;
1108  auto dta = IT->second->_calc_data;
1109  if (dta->MODEL_DATA_SET.empty())
1110  continue;
1111  file << "Data to: c" << tid << std::endl;
1112  FEXPCOMMON_FOREACH_ITER_FNC(dta->MODEL_DATA_SET,
1113  { file << "m" << std::get<0>(IT) << FEXPCOMMON_DELIMITER << "c" << std::get<1>(IT) << std::endl; });
1114  }
1115  file.close();
1116 }
1117 
1118 //--------------------------------------------------------------------------------------
1119 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1120 void CFEXPNetServer
1121 <TTClientRunner, TClientThread, Tbarrier,
1122  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1123  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1124  ::check_proc_end(size_t new_thrd_id)
1125 //--------------------------------------------------------------------------------------
1126 {
1127  if (export_results(new_thrd_id))
1128  {
1129  send_msg_and_wait(t_ENetThrdMsg::eEnd, new_thrd_id);
1130  size_t idx;
1131  FEXPCOMMON_FOREACH(size_t(t_ENetSynStgs::eStartPoint), size_t(t_ENetSynStgs::eSynchrCount) - 1, idx)
1132  _barrier_synchr_end[idx].store(true);
1133  }
1134  else
1135  send_msg_and_wait(t_ENetThrdMsg::eContinueProc, new_thrd_id);
1136 }
1137 
1140 //--------------------------------------------------------------------------------------
1141 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1142 void CFEXPNetServer
1143 <TTClientRunner, TClientThread, Tbarrier,
1144  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1145  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1146  ::Close()
1147 //--------------------------------------------------------------------------------------
1148 {
1149 #define ERROR_SOCKET_SERVER_CLOSE_CONNECT "Error: Server connection has already been closed: \n"
1150 #define ERROR_SOCKET_SERVER_CLOSE_RUNCLSE "Error: Try close server which was run and closed!!!"
1151  if(_socket_server_run_and_closed)
1153  if (!_connection_start.load())
1154  {
1155  _socket_server_run_and_closed.store(true);
1156  return;
1157  }
1158 
1159  // set close flag of closing server
1160  _flag_server_close.store(true); std::vector<Ptr<CFEXPCppThread<void(size_t), size_t>>> temp_thread_vector;
1161  auto result = CFEXPAsyncRunner::RunProcedureTask([this, &temp_thread_vector]
1162  {
1163  // set end of process (do not use synchronization --> start ending processes)
1164  size_t idx;
1165  FEXPCOMMON_FOREACH(size_t(t_ENetSynStgs::eStartPoint ),
1166  size_t(t_ENetSynStgs::eSynchrCount) - 1, idx)
1167  _barrier_synchr_end[idx].store(true);
1168  // wait until server main loop end
1169  while (!_flag_server_closed.load())
1170  {
1171  // wake up all waiting threads
1172  FEXPCOMMON_FOREACH(size_t(t_ENetSynStgs::eStartPoint ),
1173  size_t(t_ENetSynStgs::eSynchrCount) - 1, idx)
1174  {
1175  // check if any thread wait on respective barrier
1176  if (!_barrier_synchr_hit[idx].load())
1177  continue;
1178  // start temporary thread to increase thread count on barrier and thus invoke the end event (end of waiting within the barrier)
1179  auto tmpi = idx;
1181  ::SafeAllocInstance([this](auto id) { _barrier[id]->SynchronizeThreads(); }, tmpi);
1182  temp->StartThread(); temp->Detach();
1183  // thread must "start" and "end" before temporary thread variable is destroyed due to no reference
1184  temp_thread_vector.push_back(temp);
1185  }
1186  }
1187  }, false, "Waiting for closing of server main thread", true);
1188  // release all temporary threads
1189  temp_thread_vector.clear();
1190  // cancel client threads
1191  cancel_cl_threads();
1192  // close and clean up
1193  close_socket_conn();
1194  _socket_server_run_and_closed.store(true);
1196 }
1197 
1198 //--------------------------------------------------------------------------------------
1199 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1200 void CFEXPNetServer
1201 <TTClientRunner, TClientThread, Tbarrier,
1202  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1203  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1204  ::invoke_close()
1205 //--------------------------------------------------------------------------------------
1206 {
1207  // create stop file to invoke server close
1208  (std::ofstream(SERVER_STOP_FILE_NAME)).close();
1209 }
1210 
1211 //--------------------------------------------------------------------------------------
1212 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1213 void CFEXPNetServer
1214 <TTClientRunner, TClientThread, Tbarrier,
1215  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1216  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1217  ::create_socket()
1218 //--------------------------------------------------------------------------------------
1219 {
1220 #define ERROR_SERVER_SOCKET_CREATION "Error: Cannot create socket (server): \n"
1221  // information about the Windows Sockets implementation
1222  WSADATA socket_info;
1223  // initiates use of the Winsock DLL by a process
1224  auto result = WSAStartup(WINSOCKET, &socket_info);
1225  if (CONNECTION_ERRORS_1.count(result))
1226  FEXPCOMMON_EXCEPTION(ERROR_SERVER_SOCKET_CREATION + CONNECTION_ERRORS_1[result]);
1227 
1228  // fill server info for connection
1229  memset(&_socket_server_adress, FEXPCOMMON_DEFAULT_VALUE, sizeof(_socket_server_adress));
1230  _socket_server_adress.sin_family = WINNETWRK;
1231  _socket_server_adress.sin_addr.s_addr = WINANYADR;
1232  _socket_server_adress.sin_port = htons((u_short)GetCommPort());
1233  // create server socket
1234  _socket_server = socket(WINNETWRK, WINSCTYPE, WINPR_TCP/*WINPR_DMY*/);
1235  if (CONNECTION_ERRORS_2.count(result))
1236  FEXPCOMMON_EXCEPTION(ERROR_SERVER_SOCKET_CREATION + CONNECTION_ERRORS_2[result]);
1237 
1238  // associating a local address with a socket.
1239  result = bind(_socket_server, (sockaddr*)&_socket_server_adress, sizeof(_socket_server_adress));
1240  if (CONNECTION_ERRORS_4.count(result))
1241  FEXPCOMMON_EXCEPTION(ERROR_SERVER_SOCKET_CREATION + CONNECTION_ERRORS_4[result]);
1242 
1243  /*// non-blocking recv on socket
1244  struct timeval tv;
1245  tv.tv_sec = 10;
1246  if (setsockopt(_socket_server, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv))
1247  ;*/
1248 }
1249 
1250 //--------------------------------------------------------------------------------------
1251 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1252 void CFEXPNetServer
1253  <TTClientRunner, TClientThread, Tbarrier,
1254  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1255  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1256  ::start_listenning()
1257 //--------------------------------------------------------------------------------------
1258 {
1259 #define ERROR_SOCKET_SERVER_CONNECT "Error: Server cannot start: \n"
1260  if (_socket_server_run_and_closed)
1261  {
1262  auto error = ERROR_SOCKET_SERVER_CONNECT +
1263  std::string("--> Node ID") + "\"" + CFEXPBaseConvers::NumberToString<size_t>(GetId()) + "\":\n" +
1264  std::string("--> Server closed.");
1265  FEXPCOMMON_EXCEPTION(error);
1266  }
1267 
1268  // create socket and connect
1269  create_socket();
1270  // places a socket in a state in which it is listening for an incoming connection
1271  auto result = listen(_socket_server, 10);
1272  if (CONNECTION_ERRORS_5.count(result))
1273  {
1274  // throw error connection exception
1275  auto error = ERROR_SOCKET_SERVER_CONNECT +
1276  std::string("--> Node ID ") + "\"" + CFEXPBaseConvers::NumberToString<size_t>(GetId()) + "\":\n";
1277  error += CONNECTION_ERRORS_4[result];
1278  FEXPCOMMON_EXCEPTION(error);
1279  }
1280  // set server connection started
1281  _connection_start.store(true);
1282 }
1283 
1284 //--------------------------------------------------------------------------------------
1285 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1286 void CFEXPNetServer
1287 <TTClientRunner, TClientThread, Tbarrier,
1288  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1289  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1290  ::close_socket_conn()
1291 //--------------------------------------------------------------------------------------
1292 {
1293  if (_socket_server == WININVSCK)
1294  return;
1295  closesocket(_socket_server);
1296  WSACleanup();
1297  _socket_server = WININVSCK;
1298 }
1299 
1300 //--------------------------------------------------------------------------------------
1301 template<typename TTClientRunner, typename TClientThread, typename Tbarrier>
1302 void CFEXPNetServer
1303 <TTClientRunner, TClientThread, Tbarrier,
1304  typename std::enable_if<std::is_base_of<ICFEXPThreadBase , TClientThread>::value &&
1305  std::is_base_of<ICFEXPSynchrThreadBarrier, Tbarrier >::value>::type>
1306  ::cancel_cl_threads()
1307 //--------------------------------------------------------------------------------------
1308 {
1309  if (_client_thread_map.empty())
1310  return;
1311  // canceling procedure
1312  auto result = CFEXPAsyncRunner::RunProcedureTask([this]
1313  {
1314  // cancel all clients threads
1315  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map,
1316  {
1317  if (IT.second->_state)
1318  _client_thread_map[IT.first]->_thread->Cancel();
1319  });
1320  // wait for end of all client threads
1321  while (true)
1322  {
1323  size_t cancel_thread_counter = FEXPCOMMON_DEFAULT_VALUE;
1324  std::unique_lock<std::mutex> lock(_mtx_client_thread_map_update, std::defer_lock);
1325  lock.lock();
1326  FEXPCOMMON_FOREACH_ITER_FNC(_client_thread_map,
1327  {
1328  if (!IT.second->_state)
1329  ++cancel_thread_counter;
1330  });
1331  lock.unlock();
1332  // check if all threads have already been closed
1333  if (cancel_thread_counter == _client_thread_map.size())
1334  break;
1335  }
1336  }, false, "Try cancel server client threads", true);
1337  // clear thread maps
1338  _client_thread_map.clear();
1339 }
1340 
1341 #endif // !_CFEXPNETWORKSERVER_H_
#define DEFAULT_SERVER_BARRIER_COUNT
#define WINSOCKET
Definition: FEXPNetworkWinSocket.h:20
#define IT
Definition: FEXPCommon.h:155
#define GET_MAX_FLT_VAL(type)
Definition: FEXPCommon.h:205
#define WINANYADR
Definition: FEXPNetworkWinSocket.h:26
Solver configuration setting.
Definition: FEXPSetting.h:98
#define WINSCTYPE
Definition: FEXPNetworkWinSocket.h:23
#define SERVER_STOP_FILE_NAME
Name of file controling the server state (runnung/not running).
Definition: FEXPNetworkServer.h:26
Base network interface of a client node.
Definition: FEXPNetworkInterface.h:46
static Ptr< CFEXPNetServer > GetInstance(std::string server_ip, size_t port, Ptr< ICFEXPDataModelContIntf > model, Ptr< ICFEXPResultExport > exporter, Ptr< ICFEXPTransferAnalyzer > trans_analyzer)
Definition: FEXPNetworkServer.h:51
#define DEFAULT_SERVER_NODE_ID
Definition: FEXPNetworkInterface.h:19
Windows connection errors.
Definition: FEXPNetworkWinSocket.h:36
#define ERROR_SOCKET_SERVER_CONNECT
#define FEXPCOMMON_FOREACH(start, end, index)
Definition: FEXPCommon.h:153
#define FEXPCOMMON_STACAST(clsfrom, clsto, variable)
Definition: FEXPCommon.h:137
static Ptr< TType > MakeAllocInstanceSafe(TType *alloc)
Definition: FEXPCommon.h:400
#define FEXPCOMMON_FOREACH_ITER_FNC(data, lambda_body)
Definition: FEXPCommon.h:157
Definition: FEXPCommon.h:276
double t_fexpcommon_ct
Definition: FEXPCommon.h:120
Data for server clients.
Definition: FEXPNetworkInterface.h:210
ENETServerThreadMesage
Communication messages within the FEXP server.
Definition: FEXPNetworkInterface.h:155
Definition: FEXPDataContainer.h:25
#define FEXPCOMMON_DEFAULT_INDX
Definition: FEXPCommon.h:171
ENETSynchronization
Synchronization nodes within the FEXP server.
Definition: FEXPNetworkInterface.h:137
static std::enable_if< std::is_arithmetic< TValue >::value, std::string >::type NumberToString(TValue value)
Definition: FEXPCommon.h:1079
#define SERVER_TRECK_TRNS_DTA
Name of file storing of MEIM analysis results.
Definition: FEXPNetworkServer.h:29
It stores the result data.
Definition: FEXPCalculationResult.h:132
#define WININVSCK
Definition: FEXPNetworkWinSocket.h:19
#define FEXPCOMMON_EXCEPTION(error_text)
Definition: FEXPCommon.h:143
Definition: FEXPDataContainer.h:25
#define FEXPCOMMON_EMPTY_STRING
Definition: FEXPCommon.h:183
#define FEXPCOMMON_FOREACH_ITER(data)
Definition: FEXPCommon.h:156
#define ERROR_SERVER_SOCKET_CREATION
static Ptr< TType > SafeAllocInstance(VarArgs &&... inpar)
It allocates data.
Definition: FEXPCommon.h:392
#define ERROR_SOCKET_SERVER_CLOSE_RUNCLSE
#define MAP_PAIR(key, itm)
Definition: FEXPCommon.h:471
#define SERVER_NEW_CLIENT_CONNECT
CEFEXPNETProtocol::ENETSynchronization t_ENetSynStgs
Definition: FEXPNetworkInterface.h:174
Base interface for system element.
Definition: FEXPDataContainer.h:28
Base container interface.
Definition: FEXPSerializeData.h:601
#define WINNETWRK
Definition: FEXPNetworkWinSocket.h:24
#define FEXPCOMMON_DEFAULT_VALUE
Definition: FEXPCommon.h:179
static const t_FileStructMap RES_FILE_BLOCK_CLS_MAP
Definition: FEXPSerializeData.h:540
static void WriteLine()
Definition: FEXPCommon.cpp:154
Base container interface focused on processing of a serialized/deserialized data. ...
Definition: FEXPSerializeData.h:619
static bool RunProcedureTask(t_Procedure procedure, bool progressbar)
It runs the asynchronous task.
Definition: FEXPConcurency.cpp:12
Definition: FEXPNetworkServer.h:38
Smart pointer.
Definition: FEXPCommon.h:274
#define FEXPCOMMON_DYNCAST(clsfrom, clsto, variable)
Definition: FEXPCommon.h:138
#define FEXPCOMMON_DFLT_TXT
Definition: FEXPCommon.h:189
#define WINPR_TCP
Definition: FEXPNetworkWinSocket.h:21